//Random generator
//$Id: random.cpp 612 2010-11-28 18:40:53Z Oleg.Bulychov $

#include "stdafx.h"

#include "src/heo/include/random.h"

#if !defined (USE_STOC1)
#define USE_MERSENNE_TWISTER
#endif

#if defined(USE_STOC1) || defined(USE_MERSENNE_TWISTER)

//:Mersenne Twister

#include "contrib/randomc/mersenne.cpp"
#if defined(USE_STOC1)
#include "contrib/randomc/stoc1.cpp"
typedef StochasticLib1 TRandom;
void FatalError(const char *ErrorText)
{
    My_Assert(ErrorText, __FILE__, __LINE__);
    DEBUG_BREAK__;
    My_Exit(true);
}
#else
typedef CRandomMersenne TRandom;
#endif


static TRandom* g_rnd = NULL;
static int g_count = 0;

unsigned random_generator::next_UInt(unsigned uRange)
{
    return g_rnd[tid_].IRandomX(0, uRange - 1);
}

size_t random_generator::next_SizeT(size_t uRange)
{
    //TODO fix me
    return next_UInt((unsigned)uRange);
}

double random_generator::next_Double()
{
    return g_rnd[tid_].Random();
}

#if defined(USE_STOC1)
double random_generator::next_Normal(double m, double s)
{
    return g_rnd[tid_].Normal(m, s);
}
#endif

static void Free_Random()
{
    if(g_rnd)
    {
        for (int i = 0; i < g_count; ++i)
            g_rnd[i].~TRandom();
        free(g_rnd);
    }
}

void random_generator::randomize(int nMaxThreads, unsigned uSeed, int nRank)
{
    if (!g_rnd)
    {
        g_count = nMaxThreads;
        g_rnd = (TRandom*)malloc(sizeof(TRandom) * nMaxThreads);
        for (int i = 0; i < nMaxThreads; ++i)
            new(&g_rnd[i]) TRandom(uSeed);
        atexit(Free_Random);
    }
    for (int i = 0; i < nMaxThreads; ++i)
    {
        int seed[] = {uSeed, i, nRank};
        g_rnd[i].RandomInitByArray(seed, sizeof(seed)/sizeof(seed[0]));
    }
}

#else

//old Linear Congruential

static unsigned* g_RandSeed32 = NULL;

//__________________________________________________________________________________
unsigned random_generator::next_UInt(unsigned uRange)
{
    unsigned& seed = g_RandSeed32[tid_];
    seed *= 0x08088405u;
    ++seed;
    return (unsigned)(((int64_t)seed)*((int64_t)uRange) >> 32);
}
//__________________________________________________________________________________
size_t random_generator::next_SizeT(size_t uRange)
{
    //TODO fix me
    return next_UInt((unsigned)uRange);
}
//__________________________________________________________________________________
double random_generator::next_Double()
{
    return double(next_UInt(RAND_MAX)) / RAND_MAX;
}
//__________________________________________________________________________________
//double random_generator::next_Normal(double m, double s)
//{
//    ASSERT_(!"not implemented");
//    return 0;
//}
//__________________________________________________________________________________
static void Free_Random()
{
    delete[] g_RandSeed32;
}
//__________________________________________________________________________________
void random_generator::randomize(int nMaxThreads, unsigned uSeed, int nRank)
{
    if (!g_RandSeed32)
    {
        g_RandSeed32 = new unsigned[nMaxThreads];
        atexit(Free_Random);
    }
    for (int i = 0; i < nMaxThreads; ++i)
        g_RandSeed32[i] = uSeed + i + nRank * nMaxThreads;
}
//__________________________________________________________________________________
#endif

//EOF!
